using System;
using System.Collections.Generic;
using System.IO;
using System.Xml;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Content;
using System.ComponentModel;

namespace The_LarX.Rendering
{
    public class RenderManager
    {
        /// <summary>
        /// The Backbuffer Color
        /// </summary>
        public Color BackgroundColor { get; set; }

        /// <summary>
        /// Engine's GraphicsDevice
        /// </summary>
        public GraphicsDevice GraphicsDevice { get; protected set; }

        /// <summary>
        /// Used to Render Text/Sprites
        /// </summary>
        public SpriteBatch SpriteBatch { get; protected set; }

        /// <summary>
        /// Simple 128x128 Box Texture (Content\\Engine\\Textures\\tex_box)
        /// </summary>
        public Texture2D Tex { get; protected set; }

        /// <summary>
        /// Effect used to Draw Lines on the Screen
        /// </summary>
        public BasicEffect BasicEffect { get; protected set; }

        /// <summary>
        /// 2D SortMode
        /// </summary>
        public SpriteSortMode DefaultSortMode { get; set; }

        /// <summary>
        /// BlendState
        /// </summary>
        public BlendState DefaultBlendState { get; set; }

        /// <summary>
        /// Matrix used to apply the SpriteBatch to, and get a CustomResolution
        /// </summary>
        public Matrix CustomResolutionMatrix { get; protected set; }

        /// <summary>
        /// The Factor to multiply the 2D Components
        /// </summary>
        public Vector2 CustomResolutionResizeFactor { get; protected set; }

        /// <summary>
        /// If the Engine is applying a Custom resolution
        /// </summary>
        public bool ApplyCustomResolution { get; set; }

        /// <summary>
        /// Resize Sprites from a resolution to another. Good for games made in HD(1280x720), so
        /// you can turn it easy to FULL HD, or lower resolutions. Useful for porting Xbox 360 games
        /// to Windows Phone 7. 3D Graphics are adapted automatically, just 2D is different. 
        /// You have to be using LarX's rendering methods to the texture be resized.
        /// </summary>
        /// <param name="LastResHeight">The Height the Game has been made to work</param>
        /// <param name="LastResWidth">The Width the Game has been made to work</param>
        /// <param name="NewResHeight">The Height the Game will assume as a new resolution</param>
        /// <param name="NewResWidth">The Width the Game will assume as a new resolution</param>
        public void Resize2DCompsToCustomResolution(int LastResWidth, int LastResHeight,
            int NewResWidth, int NewResHeight)
        {
            float FactorX = NewResWidth / LastResWidth;
            float FactorY = NewResHeight / LastResHeight;
            CustomResolutionResizeFactor = new Vector2(FactorX, FactorY);

            CustomResolutionMatrix = Matrix.CreateScale(new Vector3(FactorX, FactorY, 1));

            ApplyCustomResolution = true;
        }

        public RenderManager(GraphicsDevice Device)
        {
            this.DefaultSortMode = SpriteSortMode.BackToFront;
            this.DefaultBlendState = BlendState.NonPremultiplied;

            this.GraphicsDevice = Device;
            this.BackgroundColor = Color.Black;
            this.SpriteBatch = new SpriteBatch(GraphicsDevice);

            this.Tex = Engine.Content.Load<Texture2D>("Engine\\Textures\\tex_box");
            this.GraphicsDevice.DeviceReset += new EventHandler<EventArgs>(GraphicsDevice_DeviceReset);

            BasicEffect = new BasicEffect(Engine.GraphicsDevice);
            BasicEffect.VertexColorEnabled = true;
        }

        void GraphicsDevice_DeviceReset(object sender, EventArgs e)
        {
            this.SpriteBatch = new SpriteBatch(GraphicsDevice);
        }

        public void Clear()
        {
            this.GraphicsDevice.Clear(BackgroundColor);            
        }

        public void Load()
        {
            this.Tex = Engine.Content.Load<Texture2D>("Engine\\Textures\\tex_box");
            this.GraphicsDevice.DeviceReset += new EventHandler<EventArgs>(GraphicsDevice_DeviceReset);

            BasicEffect = new BasicEffect(Engine.GraphicsDevice);
            BasicEffect.VertexColorEnabled = true;
        }

        #region Start SpriteBatch
        protected virtual void StartSpritebatch(Camera2D camera, bool overrideEngineResize,
            SpriteSortMode SortMode, BlendState BlendState)
        {
            if (camera != null)
            {
                if (this.ApplyCustomResolution && !overrideEngineResize)
                {
                    SpriteBatch.Begin(SortMode, BlendState, null, null, null, null, CustomResolutionMatrix * camera.World);
                }
                else
                {
                    SpriteBatch.Begin(SortMode, BlendState, null, null, null, null, camera.World);
                }
            }
            else if (this.ApplyCustomResolution)
            {
                SpriteBatch.Begin(SortMode, BlendState, null, null, null, null, CustomResolutionMatrix);
            }
            else
            {
                SpriteBatch.Begin(SortMode, BlendState);
            }
        }
        #endregion
                
        #region Sprite Rendering Methods

        #region Vector2
        public void Draw(Texture2D Texture, Vector2 Position, Camera2D camera, bool OverrideEngineResize)
        {
            Draw(Texture, Position, new Rectangle(0,0, Texture.Width,Texture.Height), 
                Color.White, 0, Vector2.Zero, Vector2.One, 
                SpriteEffects.None, 0, camera, OverrideEngineResize);
        }
        public void Draw(Texture2D Texture, Vector2 Position, Camera2D camera, 
            bool OverrideEngineResize, Color Color)
        {
            Draw(Texture, Position, new Rectangle(0, 0, Texture.Width, Texture.Height),
                Color, 0, Vector2.Zero, Vector2.One, SpriteEffects.None, 0, camera, 
                OverrideEngineResize, DefaultSortMode, DefaultBlendState);
        }
        public void Draw(Texture2D Texture, Vector2 Position, Color Color, 
            Camera2D camera, bool OverrideEngineResize, Rectangle SourceRectangle)
        {
            Draw(Texture, Position, SourceRectangle, Color, 0, Vector2.Zero, 
                Vector2.One, SpriteEffects.None, 0, camera, OverrideEngineResize, DefaultSortMode, DefaultBlendState);
        }
        public void Draw(Texture2D Texture, Vector2 Position, 
            Rectangle SourceRectangle, Color Color, float Rotation, 
            Vector2 Origin, Vector2 Scale, SpriteEffects Effects, 
            float Depth, Camera2D camera, bool OverrideEngineResize)
        {
            Draw(Texture, Position, SourceRectangle, Color, Rotation, Origin, Scale, Effects, Depth, camera, OverrideEngineResize, DefaultSortMode, DefaultBlendState);
        }
        public void Draw(Texture2D Texture, Vector2 Position, 
            Rectangle SourceRectangle, Color Color, float Rotation, 
            Vector2 Origin, Vector2 Scale, SpriteEffects Effects, 
            float Depth, Camera2D camera, bool OverrideEngineResize, 
            SpriteSortMode SortMode, BlendState BlendState)
        {
            StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
            SpriteBatch.Draw(Texture, Position, SourceRectangle, Color, Rotation, Origin, Scale, Effects, Depth);
            SpriteBatch.End();
        }        
        #endregion

        #region Rectangle
        public void Draw(Texture2D Texture, Rectangle DestinationRectangle, 
            Color Color, Camera2D camera)
        {
            Draw(Texture, DestinationRectangle, new Rectangle(0, 0, Texture.Width, Texture.Height), 
                Color, 0, Vector2.Zero, SpriteEffects.None, 0, camera, false, DefaultSortMode, DefaultBlendState);
        }
        public void Draw(Texture2D Texture, Rectangle DestinationRectangle, 
            Rectangle SourceRectangle, Color Color, float Rotation, Vector2 Origin, 
            SpriteEffects Effects, float Depth, Camera2D camera, 
            bool OverrideEngineResize, SpriteSortMode SortMode, BlendState BlendState)
        {
            StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
            SpriteBatch.Draw(Texture, DestinationRectangle, SourceRectangle, Color, Rotation, Origin, Effects, Depth);
            SpriteBatch.End();
        }
        #endregion

        #endregion

        #region String Rendering Methods
        public void DrawString(string Text, float Shadow, int ShadowAlpha, 
            Vector2 Position, string FontName, Color Color, Camera2D camera)
        {
            DrawString(Text, Shadow, ShadowAlpha, Position, 
                FontName, Color, 0, Vector2.Zero, Vector2.One, 
                0, camera, false, DefaultSortMode, DefaultBlendState);
        }
        public void DrawString(string Text, float Shadow, int ShadowAlpha, 
            Vector2 Position, string FontName, Color Color, Camera2D camera, 
            float Rotation, Vector2 Origin, float Scale, float Depth)
        {
            DrawString(Text, Shadow, ShadowAlpha, Position, 
                FontName, Color, Rotation, Origin, new Vector2(Scale), 
                Depth, camera, false, DefaultSortMode, DefaultBlendState);
        }
        public void DrawString(string Text, float Shadow, int ShadowAlpha, Vector2 Position,
            string FontName, Color Color, float Rotation, Vector2 Origin, Vector2 Scale,
            float Depth, Camera2D camera, bool OverrideEngineResize)
        {
            DrawString(Text, Shadow, ShadowAlpha, Position, 
                FontName, Color, Rotation, Origin, Scale, 
                Depth, camera, OverrideEngineResize, DefaultSortMode, DefaultBlendState);
        }
        public void DrawString(string Text, float Shadow, int ShadowAlpha, Vector2 Position, 
            string FontName, Color Color, float Rotation, Vector2 Origin, Vector2 Scale, 
            float Depth, Camera2D camera, bool OverrideEngineResize, 
            SpriteSortMode SortMode, BlendState BlendState)
        {
            if (!string.IsNullOrEmpty(Text))
            {
                if (Text.Contains("[("))
                {
                    if (Text.Contains(")]"))
                    {
                        DrawStringWithButton(Text, Shadow, ShadowAlpha, Position, FontName, 
                            Color, Rotation, Origin, Scale, Depth, Scale, camera, SortMode, BlendState);
                        return;
                    }
                }

                SpriteFont Font = Engine.FontManager.GetFont(FontName);
                if (Font == null)
                    return;

                StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
                SpriteBatch.DrawString(Font, Text, Position, Color, Rotation, Origin, Scale, 
                    SpriteEffects.None, Depth);
                if (Shadow > 0)
                {
                    Color color = Color.Black;
                    color.A = (byte)ShadowAlpha;
                    SpriteBatch.DrawString(Font, Text,
                        new Vector2(Position.X + Shadow, Position.Y + Shadow),
                        color, Rotation, Origin, Scale, SpriteEffects.None, Depth);
                }
                SpriteBatch.End();
            }
        }
        public void DrawOutlinedString(string text, Vector2 Position, string fontName, int shadow)
        {
            DrawString(text, 0, 0, Position + new Vector2(shadow, 0), fontName, Color.Black, null);
            DrawString(text, 0, 0, Position + new Vector2(-shadow, 0), fontName, Color.Black, null);
            DrawString(text, 0, 0, Position + new Vector2(0, shadow), fontName, Color.Black, null);
            DrawString(text, 0, 0, Position + new Vector2(0, -shadow), fontName, Color.Black, null);
            DrawString(text, 0, 0, Position, fontName, Color.White, null);
        }

        public void DrawStringWithButton(string Text, float Shadow, int ShadowAlpha,
            Vector2 Position, string FontName, Color Color, Camera2D camera)
        {
            DrawStringWithButton(Text, Shadow, ShadowAlpha, Position, FontName,
                Color, 0, Vector2.Zero, Vector2.One, 0, Vector2.One, camera, DefaultSortMode, DefaultBlendState);
        }
        public void DrawStringWithButton(string Text, float Shadow, int ShadowAlpha,
            Vector2 Position, string FontName, Color Color, float Rotation, Vector2 Origin,
            Vector2 Scale, float Depth, Vector2 ButtonSize, Camera2D camera)
        {
            DrawStringWithButton(Text, Shadow, ShadowAlpha, Position, FontName,
                Color, Rotation, Origin, Scale, Depth, ButtonSize, camera, DefaultSortMode, DefaultBlendState);
        }

        public void DrawStringWithButton(string Text, float Shadow, int ShadowAlpha, Vector2 Position, string FontName, 
            Color Color, float Rotation, Vector2 Origin, Vector2 Scale, float Depth, Vector2 ButtonSize, Camera2D camera,
            SpriteSortMode SortMode, BlendState BlendState)
        {
            try
            {
                string ButtonName = Engine.FontManager.Button(Text);
                string StartFrase = Text.Remove(Text.IndexOf("[("));
                int FinalIndex = Text.IndexOf(")]", 2);
                string finalButtonName = Text.Remove(0, StartFrase.Length);
                string FinalFrase = finalButtonName.Remove(0, finalButtonName.IndexOf(")]") + 2);

                SpriteFont font = Engine.FontManager.GetFont(FontName);
                SpriteFont XboxController = Engine.FontManager.GetFont("XboxController");
                // Render first string before button
                if (StartFrase != String.Empty)
                {
                    Engine.RenderManager.DrawString(StartFrase, Shadow, ShadowAlpha,
                        Position, FontName, Color, Rotation, Origin, Scale, Depth, camera, false, SortMode, BlendState);
                }

                Vector2 startFraseSize = font.MeasureString(StartFrase) * Scale;
                Vector2 buttonSize = XboxController.MeasureString(ButtonName) * ButtonSize;
                Vector2 buttonPosition = new Vector2(Position.X + startFraseSize.X, Position.Y - (buttonSize.Y / 3));

                Engine.RenderManager.DrawString(ButtonName, Shadow, ShadowAlpha, buttonPosition,
                    "XboxController", Color, Rotation, Origin, ButtonSize, Depth, camera, false, SortMode, BlendState);

                Vector2 finalFraseSize = font.MeasureString(FinalFrase) * Scale;
                Vector2 finalFrasePosition = new Vector2(buttonPosition.X + (buttonSize.X), 
                    buttonPosition.Y + (buttonSize.Y / 2) - (finalFraseSize.Y / 2));

                if (FinalFrase != String.Empty)
                {
                    Engine.RenderManager.DrawString(FinalFrase, Shadow, ShadowAlpha, finalFrasePosition,
                        FontName, Color, Rotation, Origin, Scale, Depth, camera, false, SortMode, BlendState);
                }
            }
            catch { }
        }
        #endregion

        #region Line Rendering Methods
        public void Draw2DLine(Vector2 PointOne, Vector2 PointTwo, Camera2D Camera, Color color, int Thickness)
        {
            Vector2 direction = PointTwo - PointOne;
            direction.Normalize();
            float X = PointTwo.X - PointOne.X;
            float Y = PointTwo.Y - PointOne.Y;
            float Hyp = MathUtil.Hypotenuse(X, Y);
            Rectangle rec = new Rectangle((int)PointOne.X, (int)PointOne.Y, (int)Hyp, Thickness);
            float ang = Vector2Util.ToAngle(direction);

            DrawRectangle(color, rec, Camera, ang, false, DefaultSortMode, DefaultBlendState);
        }
        #endregion

        #region Rectangle Rendering Methods

        #region Rectangle
        public void DrawRectangle(Color color, Rectangle Rectangle, Camera2D camera)
        {
            DrawRectangle(color, Rectangle, camera, false, DefaultSortMode, DefaultBlendState);
        }
        public void DrawRectangle(Color color, Rectangle Rectangle, Camera2D camera, float rotation, 
            bool OverrideEngineResize, SpriteSortMode SortMode, BlendState BlendState)
        {
            StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
            SpriteBatch.Draw(Tex, Rectangle, null, color, rotation, Vector2.Zero, SpriteEffects.None, 0);
            SpriteBatch.End();
        }
        public void DrawRectangle(Color color, Rectangle Rectangle, Camera2D camera,
            bool OverrideEngineResize, SpriteSortMode SortMode, BlendState BlendState)
        {
            Rectangle rect = Rectangle;
            StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
            SpriteBatch.Draw(Tex, rect, color);
            SpriteBatch.End();
        }
        public void DrawRectangle(Color color, Rectangle Rectangle, Camera2D camera, int Shadow, int ShadowAlpha)
        {
            Color rolor = Color.Black;
            rolor.A = (byte)ShadowAlpha;
            Rectangle rect = new Rectangle(Rectangle.X + Shadow, Rectangle.Y + Shadow,
                Rectangle.Width, Rectangle.Height);
            DrawRectangle(rolor, rect, camera, false, DefaultSortMode, DefaultBlendState);
            DrawRectangle(color, Rectangle, camera, false, DefaultSortMode, DefaultBlendState);
        }
        #endregion

        #region Float Rectangle
        public void DrawFloatRectangle(Color color, Vector2 pos, float Width, float Height, Camera2D camera,
            bool OverrideEngineResize, SpriteSortMode SortMode, BlendState BlendState)
        {
            StartSpritebatch(camera, OverrideEngineResize, SortMode, BlendState);
            SpriteBatch.Draw(Tex, pos, null, color, 0, Vector2.Zero, new Vector2(Width / Tex.Width,
                Height / Tex.Height), SpriteEffects.None, 0);
            SpriteBatch.End();
        }
        public void DrawFloatRectangle(Color color, Vector2 pos,
            float Width, float Height, Camera2D camera, int Shadow, int ShadowAlpha)
        {
            Color rolor = Color.Black;
            rolor.A = (byte)ShadowAlpha;
            DrawFloatRectangle(rolor, pos + new Vector2(Shadow), Width, Height, camera, false, DefaultSortMode, DefaultBlendState);
            DrawFloatRectangle(color, pos, Width, Height, camera, false, DefaultSortMode, DefaultBlendState);
        }
        #endregion

        #endregion

        #region Center Sprites/Textures/Text

        public float CenterTextureX(Texture2D Tex)
        {
            float width = Tex.Width;
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferWidth / 2;
            float MidTextSize = width / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextureY(Texture2D Tex)
        {
            float height = Tex.Height;
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferHeight / 2;
            float MidTextSize = height / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public Vector2 CenterTexture(Texture2D tex)
        {
            return new Vector2(CenterTextureX(tex), CenterTextureY(tex));
        }
        public float CenterSpriteX(Viewport view, Sprite2D sprite)
        {
            float width = sprite.Texture.Width * sprite.Size.X;
            float MidScreen = view.Width / 2;
            MidScreen += view.X;
            float MidTextSize = width / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterSpriteX(Rectangle view, Sprite2D sprite)
        {
            float width = sprite.Texture.Width * sprite.Size.X;
            float MidScreen = view.Width / 2;
            MidScreen += view.X;
            float MidTextSize = width / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterSpriteY(Viewport view, Sprite2D sprite)
        {
            float height = sprite.Texture.Height * sprite.Size.Y;
            float MidScreen = view.Height / 2;
            MidScreen += view.Y;
            float MidTextSize = height / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterSpriteY(Rectangle view, Sprite2D sprite)
        {
            float height = sprite.Texture.Height * sprite.Size.Y;
            float MidScreen = view.Height / 2;
            MidScreen += view.Y;
            float MidTextSize = height / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterSpriteX(Sprite2D sprite)
        {
            Vector2 size = new Vector2(sprite.Texture.Width * sprite.Size.X, 0);
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferWidth / 2;
            float MidTextSize = size.X / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterSpriteY(Sprite2D sprite)
        {
            Vector2 size = new Vector2(0, sprite.Texture.Height * sprite.Size.Y);
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferHeight / 2;
            float MidTextSize = size.Y / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public Vector2 CenterSprite(Sprite2D sprite)
        {
            return new Vector2(CenterSpriteX(sprite), CenterSpriteY(sprite));
        }
        public Vector2 CenterSprite(Viewport view, Sprite2D sprite)
        {
            return new Vector2(CenterSpriteX(view, sprite), CenterSpriteY(view, sprite));
        }
        public Vector2 CenterSprite(Rectangle view, Sprite2D sprite)
        {
            return new Vector2(CenterSpriteX(view, sprite), CenterSpriteY(view, sprite));
        }
        public float CenterTextX(string Text, string Font, float Size)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferWidth / 2;
            float MidTextSize = size.X / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextX(string Text, string Font, float Size, Rectangle Space)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = Space.Width / 2;
            float MidTextSize = size.X / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;
            finalPos += Space.X;

            return finalPos;
        }
        public float CenterTextX(string Text, string Font, float Size, int BoundsWidth)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = BoundsWidth / 2;
            float MidTextSize = size.X / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextY(string Text, string Font, float Size, Rectangle View)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = View.Height / 2;
            float MidTextSize = size.Y / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;
            finalPos += View.Y;

            return finalPos;
        }
        public float CenterTextY(string Text, string Font, float Size, int BoundsHeight)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = BoundsHeight / 2;
            float MidTextSize = size.Y / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextY(string Text, string Font, float Size)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = Engine.GraphicsDevice.PresentationParameters.BackBufferHeight / 2;
            float MidTextSize = size.Y / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextX(string Text, string Font, float Size, float ScreenWidth)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = ScreenWidth / 2;
            float MidTextSize = size.X / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }
        public float CenterTextY(string Text, string Font, float Size, float ScreenHeight)
        {
            string text = Text;
            Vector2 size = Engine.FontManager.GetFont(Font).MeasureString(text) * Size;
            float MidScreen = ScreenHeight / 2;
            float MidTextSize = size.Y / 2;
            float finalPos = MidScreen;
            finalPos -= MidTextSize;

            return finalPos;
        }

        #endregion

        #region Render To Texture

        public Texture2D TransformTextInTexture(string Text, Vector2 Position, Vector2 TexSize, string FontName,
             float Shadow, Color Color, Color BackgroundColor, float Scale)
        {
            Render2Texture Tex = new Render2Texture((int)TexSize.X, (int)TexSize.Y);
            Tex.BackgroundColor = BackgroundColor;
            Tex.ClearBackground = true;

            Tex.BeginRender();

            Engine.RenderManager.DrawString(Text, 2, 255, Position, FontName, Color, null, 0, Vector2.Zero, Scale, 0);

            Tex.EndRender();

            return Tex.RenderTarget;
        }

        #endregion

        #region String Division

        public string DivideString(string str, float InitialX, Viewport viewport, string font)
        {
            return DivideString(str, InitialX, viewport, Engine.FontManager.GetFont(font));
        }
        public string DivideString(string str, float InitialX, Viewport viewport, SpriteFont font)
        {
            if (str == null)
                return "";
            Vector2 size = font.MeasureString(str) + new Vector2(InitialX, 0);
            if (str.Length > 0)
            {
                string text = str;

                while (size.X > viewport.Width)
                {
                    text = StringUtil.RemoveLastWord(text);
                    size = font.MeasureString(text) + new Vector2(InitialX, 0);
                }

                string behindText = str.Replace(text, "");
                
                return text + "\n" + behindText;
            }
            return str;
        }
        public string DivideString(string str, float MaximumLineWidth, string font)
        {
            return DivideString(str, MaximumLineWidth, Engine.FontManager.GetFont(font));
        }
        public string DivideString(string str, float MaximumLineWidth, SpriteFont font)
        {
            if (str == null)
                return "";

            string[] words = str.Split(' ');
            string finalString = "";

            float SpaceSize = font.MeasureString(" ").X;

            float LineSize = 0;
            for (int i = 0; i < words.Length; i++)
            {
                Vector2 wordSize = font.MeasureString(words[i]);                

                if (LineSize + wordSize.X + SpaceSize < MaximumLineWidth)
                {
                    finalString += " " + words[i];
                    LineSize += wordSize.X + SpaceSize;
                }
                else
                {
                    finalString += "\n" + words[i];
                    LineSize = 0;
                }
            }

            return finalString;
        }
        public Vector2 MeasureString(string str, float MaximumLineWidth, SpriteFont font)
        {
            if (str == null)
                return Vector2.Zero;

            return font.MeasureString(DivideString(str, MaximumLineWidth, font));
        }

        public Vector2 MeasureString(string str, float InitialX, Viewport viewport, string font)
        {
            return MeasureString(str, InitialX, viewport, Engine.FontManager.GetFont(font));
        }
        public Vector2 MeasureString(string str, float InitialX, Viewport viewport, SpriteFont font)
        {
            if (str == null)
                return Vector2.Zero;
            Vector2 size = font.MeasureString(str) + new Vector2(InitialX, 0);

            if (str.Length > 0)
            {
                string text = str;

                while (size.X > viewport.Width)
                {
                    text = StringUtil.RemoveLastWord(text);
                    size = font.MeasureString(text) + new Vector2(InitialX, 0); ;
                }

                string behindText = str.Replace(text, "");
                Vector2 sizeT = font.MeasureString(behindText);

                Vector2 finalSize = new Vector2(size.X - InitialX, sizeT.Y + size.Y);

                return finalSize;
            }
            return size;
        }

        #endregion

        #region Bounding Box

        private int[] BoxIndices = new int[]
        {
            0, 1,
            1, 2,
            2, 3,
            3, 0,
            0, 4,
            1, 5,
            2, 6,
            3, 7,
            4, 5,
            5, 6,
            6, 7,
            7, 4,
        };

        public void DrawBoundingBox(BoundingBox box, Color color, Camera3D Camera)
        {
            VertexPositionColor[] vtx = new VertexPositionColor[8];
            Vector3[] corners = box.GetCorners();
            for (int i = 0; i < 8; i++)
            {
                vtx[i].Position = corners[i];
                vtx[i].Color = color;
            }

            BasicEffect.World = Matrix.Identity;
            if (Camera != null)
            {
                BasicEffect.View = Camera.View;
                BasicEffect.Projection = Camera.Projection;
            }
            else
            {
                BasicEffect.View = Matrix.Identity;
                BasicEffect.Projection = Matrix.Identity;
            }

            BasicEffect.CurrentTechnique.Passes[0].Apply();
            Engine.GraphicsDevice.DrawUserIndexedPrimitives<VertexPositionColor>(
                    PrimitiveType.LineList,
                    vtx,
                    0,
                    8,
                    BoxIndices,
                    0,
                    BoxIndices.Length / 2);
        }

        #endregion

        #region Bounding Sphere

        public void DrawBoundingSphere(BoundingSphere sphere, int Resolution, Color color, Camera3D Cam)
        {
            DrawBoundingSphere(sphere.Center, sphere.Radius, Resolution, color, Cam);
        }
        public void DrawBoundingSphere(Vector3 center, float Radius, int Resolution, Color color, Camera3D Cam)
        {
            VertexPositionColor[] verts = new VertexPositionColor[(Resolution + 1) * 3];
            int index = 0;

            float step = MathHelper.TwoPi / (float)Resolution;

            //create the loop on the XY plane first
            for (float a = 0f; a <= MathHelper.TwoPi; a += step)
            {
                verts[index++] = new VertexPositionColor(
                    new Vector3((float)Math.Cos(a), (float)Math.Sin(a), 0f),
                    Color.White);
            }
            //next on the XZ plane
            for (float a = 0f; a <= MathHelper.TwoPi; a += step)
            {
                verts[index++] = new VertexPositionColor(
                    new Vector3((float)Math.Cos(a), 0f, (float)Math.Sin(a)),
                    Color.White);
            }
            //finally on the YZ plane
            for (float a = 0f; a <= MathHelper.TwoPi; a += step)
            {
                verts[index++] = new VertexPositionColor(
                    new Vector3(0f, (float)Math.Cos(a), (float)Math.Sin(a)),
                    Color.White);
            }

            for (int i = 0; i < verts.Length; i++)
                verts[i].Color = color;
            
            if (Cam != null)
            {
                BasicEffect.View = Cam.View;
                BasicEffect.Projection = Cam.Projection;
            }
            else
            {
                BasicEffect.View = Matrix.Identity;
                BasicEffect.Projection = Matrix.Identity;
            }

            BasicEffect.World = Matrix.CreateScale(Radius) *
                Matrix.CreateTranslation(center);

            BasicEffect.DiffuseColor = color.ToVector3();

            BasicEffect.CurrentTechnique.Passes[0].Apply();
            Engine.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, verts, 0, Resolution);
        }

        #endregion

        #region 3D Line

        /// <summary>
        /// Draws a line from the specified start position to the specified end position
        /// </summary>
        /// <param name="start">The start point</param>
        /// <param name="end">The end point</param>
        /// <param name="transform">The World Matrix</param>
        public void DrawLine(Vector3 start, Vector3 end, Matrix transform, Color color, Camera3D Camera)
        {
            VertexPositionColor[] vtx = new VertexPositionColor[]
            {
                new VertexPositionColor(start, color),
                new VertexPositionColor(end, color)
            };

            BasicEffect.World = transform;

            if (Camera != null)
            {
                BasicEffect.View = Camera.View;
                BasicEffect.Projection = Camera.Projection;
            }
            else
            {
                BasicEffect.View = Matrix.Identity;
                BasicEffect.Projection = Matrix.Identity;
            }

            BasicEffect.DiffuseColor = color.ToVector3();

            BasicEffect.CurrentTechnique.Passes[0].Apply();
            Engine.GraphicsDevice.DrawUserPrimitives<VertexPositionColor>(PrimitiveType.LineList, vtx, 0, 1);
        }

        #endregion

        #region Draw Grid

        public virtual void DrawGrid(int Lines, int SpaceBetweenLines, int LineSize, Camera3D Camera)
        {
            for (int i = -Lines / 2; i < Lines - (Lines / 2); i++)
            {
                this.DrawLine(new Vector3(-LineSize, 0, i * SpaceBetweenLines), new Vector3(LineSize, 0, i * SpaceBetweenLines), Matrix.Identity,
                    Color.White, Camera);

                for (int k = 0; k < Lines; k++)
                {
                    this.DrawLine(new Vector3(i * SpaceBetweenLines, 0, -LineSize), new Vector3(i * SpaceBetweenLines, 0, LineSize), Matrix.Identity,
                    Color.White, Camera);
                }
            }
            int LinesTwo = Lines / 2;
            this.DrawLine(new Vector3(-LineSize, 0, LinesTwo), new Vector3(LineSize, 0, LinesTwo), Matrix.Identity,
                    Color.White, Camera);
            this.DrawLine(new Vector3(LinesTwo, 0, -LineSize), new Vector3(LinesTwo, 0, LineSize), Matrix.Identity,
                    Color.White, Camera);
        }
        

        #endregion
    }
}
